package com.gitee.huanminabc.fastboot.proxy;

import com.gitee.huanminabc.jcommon.reflect.ReflectPath;
import com.gitee.huanminabc.fastboot.context.AppContext;
import net.bytebuddy.implementation.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class ProxyInterceptor {
    /**
     * 拦截器方法
     *
     * @param proxy    代理对象
     * @param method   表示被代理的方法
     * @param args     方法参数
     * @param callable 原方法调用
     * @return
     */
    @RuntimeType
    public static Object intercept(@This Object proxy,
                                   @Origin Method method,
                                   @AllArguments Object[] args,
                                   @SuperCall Callable<?> callable
    ) throws Exception {
        String methodParamAllPath = ReflectPath.getMethodParamAll(method);
        List<InterceptorHandle> interceptorHandles = AppContext.interceptorHandleMap.get(methodParamAllPath);
        Class<?> realClass = ByteBuddyProxy.getRealClass(proxy.getClass());

        if (interceptorHandles != null) {
            Map<String,Object> context=new HashMap<>();
            for (InterceptorHandle interceptorHandle : interceptorHandles) {
                context.put("interceptorType",interceptorHandle.getClass());
                //执行拦截器
                interceptorHandle.before(proxy,realClass, method, args,context);
            }
            try {
                AtomicReference<Object> call = new AtomicReference<>();
                AtomicBoolean run = new AtomicBoolean(false);
                //环绕
                for (InterceptorHandle interceptorHandle : interceptorHandles) {
                    context.put("interceptorType",interceptorHandle.getClass());
                    //执行拦截器
                    call.set(interceptorHandle.around(proxy,realClass, method, args, () -> {
                        //如果已经执行过,那么直接返回
                        if (run.get()) {
                            return call.get();
                        }
                        run.set(true);//标记已经执行
                        call.set(callable.call());
                        return call.get();
                    },context));
                }
                //如果没有执行,那么就是执行原方法
                if (!run.get()) {
                    call.set(callable.call());
                }
                //后置处理
                for (InterceptorHandle interceptorHandle : interceptorHandles) {
                    context.put("interceptorType",interceptorHandle.getClass());
                    call.set(interceptorHandle.after(proxy,realClass, method, args, call.get(),context));
                }
                return call.get();
            } catch (Exception e) {
                for (InterceptorHandle interceptorHandle : interceptorHandles) {
                    context.put("interceptorType",interceptorHandle.getClass());
                    //执行拦截器
                    interceptorHandle.error(proxy,realClass, method, args, e,context);
                }
                throw e;
            }finally {
                for (InterceptorHandle interceptorHandle : interceptorHandles) {
                    context.put("interceptorType",interceptorHandle.getClass());
                    //执行拦截器
                    interceptorHandle.returnAfter(proxy,realClass, method, args,context);
                }
            }
        }else {
            //如果没有拦截器,那么直接执行原方法
            return callable.call();
        }
    }
}